package com.xbongbong.parent.abstracts;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.pojo.dto.FormDataUpdateDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.vo.FormDataUpdateVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.parent.help.CommonPermissionHelp;
import com.xbongbong.parent.interfaces.FormDataUpdateService;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.formdata.pojo.dto.FormDataDetailDTO;
import com.xbongbong.pro.formdata.pojo.vo.BeforeUpdateVO;
import com.xbongbong.pro.formdata.pojo.vo.UpdateVO;
import com.xbongbong.pro.permission.pojo.dto.VerifyUpdatePermissionDTO;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author 吴峰
 * @date 2022/01/06 14:45
 */
@Component
public abstract class AbstractParentUpdateFormDataService<F, D> implements FormDataUpdateService<F, D> {

    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractParentUpdateFormDataService.class);

    @Resource
    private CommonPermissionHelp commonPermissionHelp;

    @Override
    public FormDataUpdateVO updateAndImport( FormDataUpdateDTO formDataAddDTO) throws XbbException {
        if (Objects.equals(formDataAddDTO.getIsImport(), 1)) {
            return importData( formDataAddDTO);
        } else {
            return update( formDataAddDTO);
        }
    }

    @Override
    public FormDataUpdateVO update( FormDataUpdateDTO formDataUpdateDTO) throws XbbException {
        try {
            Long formId = formDataUpdateDTO.getFormId();
            String corpid = formDataUpdateDTO.getCorpid();
            Integer businessType = formDataUpdateDTO.getBusinessType();
            Integer saasMark = formDataUpdateDTO.getSaasMark();
            Long dataId = formDataUpdateDTO.getDataId();
            // 权限校验
            validatePermission(formDataUpdateDTO);
            // 获取表单实体
            F form = getForm(formDataUpdateDTO);
            // 获取字段解释
            List<FieldAttrEntity> explainList = getExplainList(formDataUpdateDTO, corpid, formId, saasMark, businessType);
            Map<String, FieldAttrEntity> explainMap = new HashMap<>(explainList.size());
            explainList.forEach(item->explainMap.put(item.getAttr(), item));
            // 获取数据
            D formData = getFormData(formDataUpdateDTO, explainMap);

            formDataUpdateDTO.setExplainMap(explainMap);
            JSONObject newData = formDataUpdateDTO.getDataList();
            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            BeanUtil.copyProperties(formDataUpdateDTO, validateDataDTO);
            validateDataDTO.setData(newData);
            validateDataDTO.setExplainMap(explainMap);
            validateDataDTO.setDataId(formDataUpdateDTO.getDataId());
            validateDataDTO.setOwnerIds(formDataUpdateDTO.getOwnerId());
            if(Objects.nonNull(formDataUpdateDTO.getIsCover())){
                validateDataDTO.setIsCover(formDataUpdateDTO.getIsCover());
            }
            validateDataDTO.setIsNew(true);
            formDataUpdateDTO.setCoUserId(validateDataDTO.getCoUserId());
            // 解析数据，校验必填字段，校验各个业务的逻辑
            analyticalData(formDataUpdateDTO, validateDataDTO, formData, explainMap);
            // 不要删除这行，如果需要删除这行，需要在各个业务对saasNeedRedundantAttrPoJo单独赋值
            formDataUpdateDTO.setSaasNeedRedundantAttrPoJo(validateDataDTO.getSaasNeedRedundantAttrPoJo());
            // 获取要更新的数据
            D updateData = getData(formDataUpdateDTO, formData, newData, validateDataDTO.getDepartmentId());
            // 开始工作流或者开始审批
            BeforeUpdateVO beforeUpdateVO = startWorkFlowOrProcess(updateData, formData, form, validateDataDTO.getSaasNeedRedundantAttrPoJo(), formDataUpdateDTO, explainMap, explainList);
            return updateNoValidate( beforeUpdateVO, formDataUpdateDTO, form, updateData, formData);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.error("com.xbongbong.parent.service.abstracts.AbstractParentUpdateFormDataService.update", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }


    }

    @Override
    public FormDataUpdateVO importData( FormDataUpdateDTO formDataUpdateDTO) throws XbbException {

        Long formId = formDataUpdateDTO.getFormId();
        Integer businessType = formDataUpdateDTO.getBusinessType();
        String corpid = formDataUpdateDTO.getCorpid();
        Integer saasMark = formDataUpdateDTO.getSaasMark();
        // 获取表单实体
        F form = getForm(formDataUpdateDTO);
        // 获取字段解释
        List<FieldAttrEntity> explainList = getExplainList(formDataUpdateDTO, corpid, formId, saasMark, businessType);
        Map<String, FieldAttrEntity> explainMap = new HashMap<>(explainList.size());
        explainList.forEach(item->explainMap.put(item.getAttr(), item));
        // 获取旧数据
        D oldFormData = getFormData(formDataUpdateDTO, explainMap);

        JSONObject newData = formDataUpdateDTO.getDataList();
        formDataUpdateDTO.setExplainMap(explainMap);
        ValidateDataDTO validateDataDTO = new ValidateDataDTO();
        BeanUtil.copyProperties(formDataUpdateDTO, validateDataDTO);
        List<String> attrList = formDataUpdateDTO.getAttrList();
        if (CollectionsUtil.isNotEmpty(attrList)) {
            // 部分字段导入的时候，validateDataDTO的explainMap传的是剔除了无需导入的字段map，跳过无需导入字段的通用校验
            // saasSaveHelp.beforeSave(validateDataDTO);方法后面又把全部字段的explainMap赋值给validateDataDTO，防止后面要用其它字段解释
            Map<String, FieldAttrEntity> simpleExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (String s : attrList) {
                if (explainMap.containsKey(s)) {
                    simpleExplainMap.put(s, explainMap.get(s));
                }
            }
            validateDataDTO.setExplainMap(simpleExplainMap);
        } else {
            validateDataDTO.setExplainMap(explainMap);
        }
        validateDataDTO.setData(newData);
        validateDataDTO.setDataId(formDataUpdateDTO.getDataId());
        validateDataDTO.setOwnerIds(formDataUpdateDTO.getOwnerId());
        validateDataDTO.setIsNew(false);
        if(Objects.nonNull(formDataUpdateDTO.getIsCover())){
            validateDataDTO.setIsCover(formDataUpdateDTO.getIsCover());
        }
        formDataUpdateDTO.setCoUserId(validateDataDTO.getCoUserId());

        // 进行校验并且放入无需导入的字段
        importAnalyticalData(validateDataDTO, oldFormData, explainMap, formDataUpdateDTO);
        // 不要删除这行，如果需要删除这行，需要在各个业务对saasNeedRedundantAttrPoJo单独赋值
        formDataUpdateDTO.setSaasNeedRedundantAttrPoJo(validateDataDTO.getSaasNeedRedundantAttrPoJo());
        // 拼装导入更新的数据
        D updateData = getImportData(formDataUpdateDTO, explainMap, oldFormData, newData, validateDataDTO.getDepartmentId());
        // 校验是否触发工作流
        BeforeUpdateVO beforeUpdateVO = startWorkFlow(updateData, oldFormData, form, validateDataDTO.getSaasNeedRedundantAttrPoJo(), formDataUpdateDTO, explainMap, explainList);

        return updateNoValidate( beforeUpdateVO, formDataUpdateDTO, form, updateData, oldFormData);
    }



    private FormDataUpdateVO updateNoValidate( BeforeUpdateVO beforeUpdateVO, FormDataUpdateDTO formDataUpdateDTO, F form, D formData, D oldFormData) throws XbbException {
        Integer businessType = formDataUpdateDTO.getBusinessType();
        if (formDataUpdateDTO.getIsSatisfyTrigger()) {
            String pojo = JSON.toJSONString(beforeUpdateVO.getSaasNeedRedundantAttrPojo(), SerializerFeature.DisableCircularReferenceDetect);
            SaasNeedRedundantAttrPojo needRedundantAttrPojo = JSON.parseObject(pojo, SaasNeedRedundantAttrPojo.class);
            // 获取下
            Integer flowStatus = getFlowStatus(formData);

            // 此处不更新flowStatus，避免用户无改动数据时，审批通过的数据flowStatus从2改成1，导致触发工作流
            UpdateVO updateVO = updateForWorkflow(formDataUpdateDTO, beforeUpdateVO, form, formData, oldFormData);
            // 是否真的编辑，true是
            boolean isEdit = Objects.equals(updateVO.getUpdateLine(), 1);

            //如果团队有需审批字段，数据有改动，也触发工作流
            isEdit = isEdit || formDataUpdateDTO.getTeamIsEdit();
            if (isEdit) {
                // 真的编辑了走工作流
                FormDataUpdateVO formDataSaveVO = afterSaveForWorkflow(formDataUpdateDTO, beforeUpdateVO, updateVO, form, formData, oldFormData);
                formDataSaveVO.setFormDataId(updateVO.getDataId());
                formDataSaveVO.setBackupDataId(beforeUpdateVO.getBackupDataId());
                beforeUpdateVO.setSaasNeedRedundantAttrPojo(needRedundantAttrPojo);
                // 改审批状态
                updateFlowStatus(flowStatus, formDataUpdateDTO.getCorpid(), formDataUpdateDTO.getDataId(), formDataUpdateDTO.getSaasMark(), businessType);
                workflowUpdateTrigger(formDataUpdateDTO, beforeUpdateVO, formDataSaveVO, formData, oldFormData);
                return formDataSaveVO;
            } else {
                // 不走工作流
                // 补充在updateForWorkflow中剔除的文件柜逻辑
                if (Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType)) {
                    saveFile(beforeUpdateVO.getExplainMap(), formData, formDataUpdateDTO.getBusinessType(), updateVO.getUserVO());
                } else {
                    saveFile(beforeUpdateVO.getExplainMap(), formData, formDataUpdateDTO.getBusinessType(), updateVO.getUserVO());
                }
                FormDataUpdateVO formDataSaveVO = afterSave(formDataUpdateDTO, beforeUpdateVO, updateVO, form, formData, oldFormData);
                formDataSaveVO.setFormDataId(updateVO.getDataId());
                return formDataSaveVO;
            }
        } else {

            // TODO 经销商没加
            UpdateVO updateVO = update(formDataUpdateDTO, beforeUpdateVO, form, formData, oldFormData);

            return afterSave(formDataUpdateDTO, beforeUpdateVO, updateVO, form, formData, oldFormData);
        }
    }

    /**
     * // 为了保证用户在有修改数据的时候才触发工作流，将flowStatus进行分开更新
     * 由业务各自实现
     * @param flowStatus
     * @param corpid
     * @param dataId
     * @param saasMark
     * @param businessType
     * @throws XbbException
     */
    protected void updateFlowStatus(Integer flowStatus, String corpid, Long dataId, Integer saasMark, Integer businessType) throws XbbException{


    }
    /**
     * 判断当前人有没有编辑的数据权限
     *
     * @param formDataUpdateDTO
     * @param explainMap
     * @param oldPaasFormDataEntity
     * @return
     */
    protected void handleEditDataPermission(FormDataUpdateDTO formDataUpdateDTO, Map<String, FieldAttrEntity> explainMap, D oldPaasFormDataEntity) throws XbbException {
        FormDataDetailDTO formDataDetailDTO = new FormDataDetailDTO();
        formDataDetailDTO.setBusinessType(formDataUpdateDTO.getBusinessType());
        formDataDetailDTO.setSaasMark(formDataUpdateDTO.getSaasMark());
        formDataDetailDTO.setMenuId(formDataUpdateDTO.getMenuId());
        formDataDetailDTO.setLoginUser(formDataUpdateDTO.getLoginUser());
        formDataDetailDTO.setDistributorMark(formDataUpdateDTO.getDistributorMark());
        formDataDetailDTO.setDataId(formDataUpdateDTO.getDataId());
        PaasFormDataEntityExt paasFormDataEntityExt = (PaasFormDataEntityExt) oldPaasFormDataEntity;
        formDataDetailDTO.setDataCreatorId(paasFormDataEntityExt.getCreatorId());
        VerifyUpdatePermissionDTO verifyUpdatePermissionDTO = new VerifyUpdatePermissionDTO(formDataDetailDTO.getLoginUser(), paasFormDataEntityExt);
        boolean dataEditPermission = commonPermissionHelp.checkEditPermission(formDataDetailDTO, verifyUpdatePermissionDTO, explainMap);
        if (!dataEditPermission) {
            throw new XbbException(UserTeamErrorCodeEnum.API_ERROR_271039);
        }
    }

    protected Integer getFlowStatus(D formData) {
        return 0;
    }
}
